package com.zonta.finance.serivce.impl;


import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zonta.finance.common.exception.BizException;
import com.zonta.finance.common.service.TokenService;
import com.zonta.finance.common.utils.DateUtil;
import com.zonta.finance.config.ObjectConvertor;
import com.zonta.finance.constant.RedisKeyConstant;
import com.zonta.finance.domain.dto.AdminDTO;
import com.zonta.finance.domain.form.CreateSysResourceForm;
import com.zonta.finance.domain.form.DelSysResourceForm;
import com.zonta.finance.domain.form.ListSysResourceForm;
import com.zonta.finance.domain.form.UpdateSysResourceForm;
import com.zonta.finance.domain.po.SysResource;
import com.zonta.finance.domain.vo.GetSysResourceVo;
import com.zonta.finance.domain.vo.ListSysResourceVo;
import com.zonta.finance.mapper.SysResourceMapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zonta.finance.serivce.ISysResourceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统资源 服务实现类
 * </p>
 *
 * @author zonta
 * @since 2024-07-25
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SysResourceServiceImpl extends ServiceImpl<SysResourceMapper, SysResource> implements ISysResourceService {

    private final ObjectConvertor objectConvertor;
    private final TokenService<AdminDTO> tokenService;
    private final ObjectMapper objectMapper;
    private final RedisTemplate<String, Object> redisTemplate;
    private final RedissonClient redissonClient;

    /**
     * 创建资源
     * @param form 上级资源id
     * @return
     */
    @Override
    public Boolean createByFrom(CreateSysResourceForm form) {
        SysResource sysResource = objectConvertor.toSysResource(form);
        sysResource.initDefault();
        sysResource.setMemberId(tokenService.getThreadLocalUserId());
        sysResource.setUpdateMemberId(tokenService.getThreadLocalUserId());
        RLock rLock = redissonClient.getLock(RedisKeyConstant.CHANGE_RESOURCE_LOCK);
        try {
          rLock.lock();
            SysResource sysResourceByPath = getByPath(form.getPath());
            if (ObjUtil.isNotEmpty(sysResourceByPath)){
                throw new BizException("该资源路径已存在");
            }
            if (form.getPid()>0){
                SysResource parentSysResource = getById(form.getPid());
                if (ObjUtil.isEmpty(parentSysResource)){
                    throw new BizException("上级资源不存在");
                }
                if (parentSysResource.getPid()>0){
                    throw new BizException("不能创建三级资源");
                }
                checkPath(parentSysResource.getPath(),form.getPath());
            }else {
                checkPath(form.getPath(),null);
            }
            return save(sysResource);
        }finally {
            rLock.unlock();
        }
    }


    @Override
    public Boolean UpdateByFrom(UpdateSysResourceForm form) {
        RLock rLock = redissonClient.getLock(RedisKeyConstant.CHANGE_RESOURCE_LOCK);
        try {
            rLock.lock();
            SysResource sysResource = getById(form.getId());
            if (ObjUtil.isEmpty(sysResource)) {
                throw new BizException("资源不存在");
            }
            SysResource sysResourceByPath = getByPath(form.getPath());
            if (sysResourceByPath != null && !sysResourceByPath.getId().equals(form.getId())) {
                throw new BizException("该资源路径已存在");
            }
            SysResource parentSysResource = getById(sysResource.getPid());
            if (parentSysResource == null) {
                checkPath(form.getPath(), null);
            } else {
                checkPath(parentSysResource.getPath(), form.getPath());
            }
            LambdaUpdateWrapper<SysResource> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(SysResource::getName,form.getName())
                    .set(SysResource::getPath,form.getPath())
                    .set(SysResource::getUpdateMemberId,tokenService.getThreadLocalUserId())
                    .set(SysResource::getUpdateTime, DateUtil.getSystemTime())
                    .eq(SysResource::getId,form.getId());
            return update(wrapper);
        }catch (Exception e){
            throw e;
        } finally {
            rLock.unlock();
        }
    }

    /**
     * 查看资源列表
     * @param form
     * @return
     */
    @Override
    public List<ListSysResourceVo> getListByFrom(ListSysResourceForm form) {
        LambdaQueryWrapper<SysResource> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(form.getName())){
            wrapper.like(SysResource::getName,form.getName());
        }
        if (StrUtil.isNotEmpty(form.getPath())){
            wrapper.like(SysResource::getPath,form.getPath());
        }
        List<SysResource> sysResources = list(wrapper);
        List<ListSysResourceVo> listSysResourceVos = objectConvertor.toListSysResourceVo(sysResources);
        List<ListSysResourceVo> parentList = listSysResourceVos.stream()
                .filter(p -> p.getPid() == 0).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(parentList)) {
            return listSysResourceVos;
        }
        for (ListSysResourceVo parent : parentList) {
            List<ListSysResourceVo> childList = listSysResourceVos.stream()
                    .filter(p -> Integer.compare(parent.getId(), p.getPid()) == 0)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(childList)) {
                parent.setChildren(childList);
            }

        }
        return parentList;
    }

    /**
     * 删除资源
     * @param form
     * @return
     */
    @Override
    public Boolean delByFrom(DelSysResourceForm form) {
        RLock rLock = redissonClient.getLock(RedisKeyConstant.CHANGE_RESOURCE_LOCK);
        try {
            rLock.lock();
            if (countByPid(form.getId())>0){
                throw new BizException("该资源下面还有子资源，不能删除");
            }
            LambdaUpdateWrapper<SysResource> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(SysResource::getDelFlag,true)
                    .set(SysResource::getUpdateMemberId,tokenService.getThreadLocalUserId())
                    .set(SysResource::getUpdateTime,DateUtil.getSystemTime())
                    .eq(SysResource::getId,form.getId());
            return update(wrapper);
        }catch (Exception e){
            throw e;
        }finally {
            rLock.unlock();
        }
    }

    @Override
    public GetSysResourceVo get(Integer id) {
        SysResource sysResource = getById(id);
        if (ObjUtil.isEmpty(sysResource)){
            throw new BizException("资源不存在！");
        }
        GetSysResourceVo result = objectConvertor.toGetSysResourceVo(sysResource);
        if (sysResource.getPid()>0) {
            SysResource parentSysResource = getById(sysResource.getPid());
            if (parentSysResource == null) {
                throw new BizException("上级资源不存在");
            }
            result.setParentName(parentSysResource.getName());
        }else {
            result.setParentName("无上级资源");
        }
        return result;
    }

    /**
     * 根据pid统计子节点数量
     *
     * @param pid
     * @return
     */
    private int countByPid(int pid) {
        LambdaQueryWrapper<SysResource> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysResource::getPid,pid);
        return count(wrapper);
    }
    /**
     * 根据id获取资源
     *
     * @param path
     * @return
     */
    private SysResource getByPath(String path) {
        LambdaQueryWrapper<SysResource> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysResource::getPath,path);
        return getOne(wrapper);
    }
    /**
     * 检查path是否合法
     *
     * @param parentPath
     * @param childPath
     * @return
     */
    private boolean checkPath(String parentPath, String childPath) {
        if (parentPath == null) {
            throw new BizException("资源路径格式不正确");
        }
        // 检查路径格式
        String parentRegex = "^/[a-zA-Z0-9_*-]+(?:/[a-zA-Z0-9_*-]+)*/\\*+$";
        if (!parentPath.matches(parentRegex)) {
            throw new BizException("资源路径格式不正确");
        }
        if (childPath == null) {
            return true;
        }
        // 获取/*之前的内容
        String prefix = parentPath.substring(0, parentPath.lastIndexOf("/") + 1);
        if (!childPath.startsWith(prefix)) {
            throw new BizException("资源路径格式不正确");
        }
        String childRegex = "^/[a-zA-Z0-9_*-]+(?:/[a-zA-Z0-9_*-]+)*$";

        if (!childPath.matches(childRegex)) {
            throw new BizException("资源路径格式不正确");
        }
        return true;
    }
}
